﻿#pragma once
#include "stdafx.h"
#include "ExportViewerExeInterface.h"
#include <windows.h>
#include <winuser.h>
#include <iostream>
#include <shellapi.h>
#include <io.h>
#include "ExportViewerExeStringDefine.h"
#include "atlconv.h"
#include <iostream>  
#include <fstream>  
#include "..\MLCtrlLib\StringConvert.h"
#include "..\ModelObj\ModelObjOption.h"
#include <atlstr.h>
#include <MAPIWin.h>


#ifdef MODELLAYER_ACTIVEX

#define APP_DIRECTIRON  L""  

#else

#define APP_DIRECTIRON  L""

#endif 

ExportViewerExeInterface::ExportViewerExeInterface(void)
{
	CString szExePath,szInstallDir=_T("");
	GetModuleFileName(NULL,szExePath.GetBufferSetLength(MAX_PATH+1),MAX_PATH);
	szExePath.ReleaseBuffer();
	int pos = szExePath.ReverseFind('\\');
	if (pos>=0)
	{
		m_sSoftInStallDir = szExePath.Left(pos);
	}
	m_Gbk_EvbFilePath = m_sSoftInStallDir+ APP_DIRECTIRON + L"\\Package_Gbk.evb";
	m_Utf_EvbFilePath = m_sSoftInStallDir+ APP_DIRECTIRON + L"\\Package_Utf.evb";
}


ExportViewerExeInterface::~ExportViewerExeInterface(void)
{
}

bool ExportViewerExeInterface::ExecutePackage() 
{ 
	WriteEvbFile();

	string sExePath=WStringToString(m_EvbconsoleExePath);
	string sEvbPath=WStringToString(m_Utf_EvbFilePath);
	CString szExePath,szEvbPath;
	StdstringToCString(sExePath, szExePath);
	StdstringToCString(sEvbPath, szEvbPath);
	CString szCmd= _T("\"")+szExePath+_T("\"");
	szCmd +=_T(" ");
	szCmd +=_T("\"")+szEvbPath+_T("\"");
	CString sDir = (m_sSoftInStallDir+ APP_DIRECTIRON).c_str();
	CString szFileName = m_packagedExePath.c_str();
	CString szFileNewName = szFileName+".new"; 
	string pFileName = CStringToStdstring(szFileName);	
	string pFileNewName = CStringToStdstring(szFileNewName);
	DeleteFile(m_packagedExePath.c_str());

	SECURITY_ATTRIBUTES sa;//管道安全属性
	HANDLE hRead,hWrite;
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = TRUE;
	if (!CreatePipe(&hRead,&hWrite,&sa,0))
	{
		cout<<"Error On CreatePipe()"<<endl;
		RenameExeAndDllFile(false);
		//删除打包工程文件;
		DeleteFile(m_sMdlPath);
		return false;
	} 

	STARTUPINFO si;
	PROCESS_INFORMATION pi; 
	si.cb = sizeof(STARTUPINFO);
	GetStartupInfo(&si); 
	si.hStdError = hWrite;
	si.hStdOutput = hWrite;
	si.wShowWindow = SW_HIDE;//窗口隐藏
	si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	if (!CreateProcess(NULL,(LPTSTR)(szCmd.GetString()),NULL,NULL,TRUE,0,NULL,sDir,&si,&pi)) 
	{
		cout<<"Error On CreateProcess()"<<endl;
		//删除打包工程文件;
		RenameExeAndDllFile(false);
		RemoveEvbFiles();
		return false;
	}
	CloseHandle(hWrite);

	char buffer[4096] = {0};//读取到的输出信息
	DWORD bytesRead; 
	while (1)
	{
		ReadFile(hRead,buffer,4095,&bytesRead,NULL);

		if (WaitForSingleObject(pi.hThread,0) == WAIT_OBJECT_0)
		{
			//删除打包工程文件;
			RenameExeAndDllFile(false);
 			DeleteFile(m_sMdlPath);
			if (rename(pFileName.c_str(),pFileNewName.c_str())  == 0)
			{
				rename(pFileNewName.c_str(),pFileName.c_str());		
				return true;
			}
			break;
		}
	}
	

	return false;
	//char buffer[4096] = {0};//读取到的输出信息
	//DWORD bytesRead; 
	//while (true)
	//{
	//	ReadFile(hRead,buffer,4095,&bytesRead,NULL);
	//		
	//	if (rename(pFileName.c_str(),pFileNewName.c_str())  == 0)
	//	{
	//		rename(pFileNewName.c_str(),pFileName.c_str());
	//		break;
	//	}
	//	//输出打包过程信息
	//	cout<<buffer<<endl;
	//} 
}

void ExportViewerExeInterface::WriteEvbFile()
{

	rapidxml::xml_node<WCHAR>* rot = m_doc.allocate_node(rapidxml::node_pi,m_doc.allocate_string(L"xml version='1.0' encoding='utf-8'"));
	m_doc.append_node(rot);
	rapidxml::xml_node<WCHAR>* RootElement = m_doc.allocate_node(rapidxml::node_element,L"evb",NULL);
	m_doc.append_node(RootElement);
	RootElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_INPUTFILE,m_doc.allocate_string(m_unPackagedExePath.c_str())));
	RootElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_OUTPUTFILE,m_doc.allocate_string(m_packagedExePath.c_str())));
	rapidxml::xml_node<WCHAR>* FilesElement = m_doc.allocate_node(rapidxml::node_element,EVB_FILES,NULL);
	RootElement->append_node(FilesElement);
	FilesElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_ENABLED,L"true"));
	FilesElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_DELETEEXTRACTED,L"true"));
	FilesElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_COMPRESSFILES,L"false"));
	rapidxml::xml_node<WCHAR>* FilesElement1 = m_doc.allocate_node(rapidxml::node_element,EVB_FILES,NULL);
	FilesElement->append_node(FilesElement1);
	rapidxml::xml_node<WCHAR>* FileElement = m_doc.allocate_node(rapidxml::node_element,EVB_FILE,NULL);
	FilesElement1->append_node(FileElement);
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_TYPE ,L"3"));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_NAME ,L"%DEFAULT FOLDER%"));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_ACTION ,L"0"));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_OVERWRITEDATETIME ,L"false"));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_OVERWRITEATTRIBUTES ,L"false"));
	rapidxml::xml_node<WCHAR>* FilesElement2 = m_doc.allocate_node(rapidxml::node_element,EVB_FILES,NULL);
	FileElement->append_node(FilesElement2);

	for (int i=0;i!=m_fileVec.size();++i)
	{
		wstring filePath = m_fileVec.at(i);
		LPCWSTR lpath = filePath.c_str(); 

		DWORD dwAttrs = GetFileAttributes(lpath);//判断路径是否为目录
		if ((dwAttrs != DWORD(-1)) && (0 != (dwAttrs & FILE_ATTRIBUTE_DIRECTORY)))
		{
			bool res = CreateXmlElement(FilesElement2,filePath);
		}
		else
		{
			AddFileNode(FilesElement2,filePath);
		}
	}

	rapidxml::xml_node<WCHAR>* RegisElement = m_doc.allocate_node(rapidxml::node_element,EVB_REGISTRIES,NULL);
	RootElement->append_node(RegisElement);
	RegisElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_ENABLED,L"false"));
	rapidxml::xml_node<WCHAR>* RegisElement1 = m_doc.allocate_node(rapidxml::node_element,EVB_REGISTRIES,NULL);
	RegisElement->append_node(RegisElement1);

	rapidxml::xml_node<WCHAR>* RegiElement = m_doc.allocate_node(rapidxml::node_element,EVB_REGISTRY,NULL);
	RegisElement1->append_node(RegiElement);
	RegiElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_TYPE ,L"1"));
	RegiElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_VIRTUAL ,L"true"));
	RegiElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_NAME ,L"Classes"));
	RegiElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_VALUETYPE ,L"0"));

	rapidxml::xml_node<WCHAR>* RegiElement1 = m_doc.allocate_node(rapidxml::node_element,EVB_REGISTRY,NULL);
	RegisElement1->append_node(RegiElement1);
	RegiElement1->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_TYPE ,L"1"));
	RegiElement1->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_VIRTUAL ,L"true"));
	RegiElement1->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_NAME ,L"Classes"));
	RegiElement1->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_VALUETYPE ,L"0"));

	rapidxml::xml_node<WCHAR>* RegiElement2 = m_doc.allocate_node(rapidxml::node_element,EVB_REGISTRY,NULL);
	RegisElement1->append_node(RegiElement2);
	RegiElement2->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_TYPE ,L"1"));
	RegiElement2->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_VIRTUAL ,L"true"));
	RegiElement2->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_NAME ,L"Classes"));
	RegiElement2->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_VALUETYPE ,L"0"));

	rapidxml::xml_node<WCHAR>* RegiElement3 = m_doc.allocate_node(rapidxml::node_element,EVB_REGISTRY,NULL);
	RegisElement1->append_node(RegiElement3);
	RegiElement3->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_TYPE ,L"1"));
	RegiElement3->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_VIRTUAL ,L"true"));
	RegiElement3->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_NAME ,L"Classes"));
	RegiElement3->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_VALUETYPE ,L"0"));

	rapidxml::xml_node<WCHAR>* RegiElement4 = m_doc.allocate_node(rapidxml::node_element,EVB_REGISTRY,NULL);
	RegisElement1->append_node(RegiElement4);
	RegiElement4->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_TYPE ,L"1"));
	RegiElement4->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_VIRTUAL ,L"true"));
	RegiElement4->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_NAME ,L"Classes"));
	RegiElement4->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_VALUETYPE ,L"0"));

	rapidxml::xml_node<WCHAR>* PackElement = m_doc.allocate_node(rapidxml::node_element,EVB_PACKAGING,NULL);
	RootElement->append_node(PackElement);
	PackElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_ENABLED ,L"false"));

	rapidxml::xml_node<WCHAR>* OptionElement = m_doc.allocate_node(rapidxml::node_element,EVB_OPTIONS,NULL);
	RootElement->append_node(OptionElement);
	OptionElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_SHAREVIRTUALSYSTEM ,L"false"));
	OptionElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_MAPEXECUTABLE ,L"true"));
	OptionElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_ALLOWRUNNING ,L"true"));

	//写入文件
#ifdef UNICODE  
	std::wofstream xml_file(m_Gbk_EvbFilePath);  
	xml_file.imbue(std::locale("CHS"));  
#else  
	std::ofstream xml_file(m_Gbk_EvbFilePath);  
#endif  

	rapidxml::print((std::basic_ostream<WCHAR>&)xml_file, m_doc, 0);

	xml_file.close();

	//文件转换
	Gb2312FileToUtf8File(WStringToString(m_Gbk_EvbFilePath),WStringToString(m_Utf_EvbFilePath));

}

void ExportViewerExeInterface::Gb2312FileToUtf8File(string &strGb2312InFile, string &strUtf8OutFile )
{

	ifstream infile(strGb2312InFile,ios::in);
	if(!infile.good())
	{
		return;
	}

	ofstream outfile(strUtf8OutFile,ios::out);
	if(!outfile.good())
	{
		return;
	}

	while( !infile.fail() )
	{
		string strInLine;
		getline(infile,strInLine);

		int len = MultiByteToWideChar(CP_ACP, 0, strInLine.c_str(), -1, NULL, 0);
		wchar_t* wstr = new wchar_t[len + 1];
		memset(wstr, 0, len + 1);
		MultiByteToWideChar(CP_ACP, 0, strInLine.c_str(), -1, wstr, len);
		len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
		char* str = new char[len + 1];
		memset(str, 0, len + 1);
		len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
		if (wstr) 
			delete[] wstr;
		str[len] = '\n';

		string strOutLine = str;
		delete[] str;

		outfile<<strOutLine<<"\n";

	}

	infile.close();
	outfile.close();
}

bool ExportViewerExeInterface::CreateXmlElement(rapidxml::xml_node<WCHAR> *elem,const wstring &filePath)
{
	WIN32_FIND_DATA FileData; 
	HANDLE hSearch; 
	BOOL fFinished = FALSE; 
	wstring strtemp;  
	wstring token = L".";  
	wstring tokend = L".."; 

	//文件不存在
	if( (_waccess( filePath.c_str(), 0 )) == -1 )
	{
		return false;
	}

	int iPos = filePath.rfind('\\');
	wstring fileName = filePath.substr(iPos+1,string::npos);

	//增加文件夹节点
	rapidxml::xml_node<WCHAR>* FileElement = m_doc.allocate_node(rapidxml::node_element,EVB_FILE,NULL);
	elem->append_node(FileElement);
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_TYPE ,L"3"));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_NAME,m_doc.allocate_string(fileName.c_str())));
	if ( fileName == L"ModelLayering_User_Manual.CHM" || fileName == L"Template.docm" )
	{
		FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_ACTION ,L"1"));
	}
	else
	{
		FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_ACTION ,L"0"));
	}
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_OVERWRITEDATETIME ,L"false"));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_OVERWRITEATTRIBUTES ,L"false"));
	rapidxml::xml_node<WCHAR>* FilesElement = m_doc.allocate_node(rapidxml::node_element,EVB_FILES,NULL);
	FileElement->append_node(FilesElement);

	wstring strFile = filePath + L"\\*.*";

	LPCWSTR lfile = strFile.c_str(); 

	hSearch = FindFirstFile(lfile, &FileData); 
	if (hSearch == INVALID_HANDLE_VALUE) 
	{ 
		cout<<"No files found";
		return false;
	} 

	while (!fFinished) 
	{ 
		strtemp = FileData.cFileName; 

		if ((strtemp != token)&& (strtemp != tokend))
		{
			wstring strFile = filePath + L"\\" + strtemp;

			//如果当前文件是目录文件，则递归调用CreateXmlElement  
			if((FileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY))  
			{  
				bool res = CreateXmlElement(FilesElement,strFile);
				if (!res)
					return false;
			}  

			//非目录文件,则增加文件节点
			else 
			{
				AddFileNode(FilesElement,strFile);
			}
		}

		if (!FindNextFile(hSearch, &FileData)) 
		{
			if (GetLastError() == ERROR_NO_MORE_FILES) 
				fFinished = TRUE; 
			else 
				return false;
		}
	} 

	FindClose(hSearch);
	return true;
}

void ExportViewerExeInterface::AddFileNode(rapidxml::xml_node<WCHAR>* parentNode,const wstring filePath)
{
	int iPos = filePath.rfind('\\');
	wstring fileName = filePath.substr(iPos+1,string::npos);

	rapidxml::xml_node<WCHAR>* FileElement = m_doc.allocate_node(rapidxml::node_element,EVB_FILE,NULL);
	parentNode->append_node(FileElement);
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_TYPE,L"2"));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_NAME,m_doc.allocate_string(fileName.c_str())));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_FILE,m_doc.allocate_string(filePath.c_str())));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_ACTIVEX,L"false"));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_ACTIVEXINSTALL,L"false"));
	if ( fileName == L"ModelLayering_User_Manual.CHM" || fileName == L"Template.docm" )
	{
		FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_ACTION ,L"1"));
	}
	else
	{
		FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_ACTION ,L"0"));
	}
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_OVERWRITEDATETIME,L"false"));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_OVERWRITEATTRIBUTES,L"false"));
	FileElement->append_node(m_doc.allocate_node(rapidxml::node_element,EVB_PASSCOMMANDLINE,L"false"));
}

void ExportViewerExeInterface::RemoveEvbFiles()
{
	remove(WStringToString(m_Gbk_EvbFilePath).c_str());
	remove(WStringToString(m_Utf_EvbFilePath).c_str());
}
wstring ExportViewerExeInterface::GetEnigmavbconsoleFullPath()
{
	wstring sRetPath=m_sSoftInStallDir+ APP_DIRECTIRON +L"\\enigmavbconsole.exe";

	return sRetPath;
}

void ExportViewerExeInterface::RenameExeAndDllFile(bool bDll2Exe)
{
	wstring sDir=m_sSoftInStallDir.c_str();
	sDir = sDir+APP_DIRECTIRON;
	string stdDir = WStringToString(sDir);
	string sDllFile = stdDir+"\\ModelLayerViewer.dll" ;
	string sExeFile=stdDir +"\\ModelLayerViewer.exe" ;  //ModelLayerViewer.exe
	if (bDll2Exe)
	{
		rename(sDllFile.c_str(),sExeFile.c_str());	
	}
	else
	{
		rename(sExeFile.c_str(),sDllFile.c_str());	
	}
}

bool ExportViewerExeInterface::WriteMdlNameToFile(CString sNewMdlPath)
{
	int nPos = sNewMdlPath.ReverseFind('\\');
	if (nPos != -1)
	{
		CString sFileName = sNewMdlPath.Right(sNewMdlPath.GetLength()-nPos-1);
		CString sFilePath = sNewMdlPath.Left(nPos) +_T("\\MdlName.txt");
		ofstream io;
		io.open(sFilePath);
		io << CStringToStdstring(sFileName);
		io.close();
		return true;
	}

	return false;
}

CString ExportViewerExeInterface::Execute()
{
	wstring sUnPackagedExePath=m_sSoftInStallDir+ APP_DIRECTIRON +L"\\ModelLayerViewer.exe";    
	RenameExeAndDllFile(true);
	wstring sViewerExe=GetEnigmavbconsoleFullPath();
	if (!::PathFileExists(sViewerExe.c_str()) || !::PathFileExists(sUnPackagedExePath.c_str()))
	{
		return _T("");
	}

	SetUnPackagedExePath(sUnPackagedExePath);

	CMainFrame* pFrame = (CMainFrame*) AfxGetMainWnd();
	CChildFrame *pActiveWnd = (CChildFrame *)pFrame->MDIGetActive();
	CDocument* pDoc=pActiveWnd->GetActiveDocument();
	CString sMdlPath= pDoc->GetPathName();
	CString sExePath = (m_sSoftInStallDir+ APP_DIRECTIRON +L"\\temp.exe").c_str();
	if (::PathFileExists(sMdlPath))
	{
		CString sMdlName = _T("temp.mdl");
		CString sNewMdlPath= (m_sSoftInStallDir+ APP_DIRECTIRON +L"\\temp.mdl").c_str();
		int nPos = sMdlPath.ReverseFind('.');
		if (nPos != -1)
		{
			sExePath = sMdlPath.Left(nPos)+_T(".exe");
			nPos = sMdlPath.ReverseFind('\\');
			sMdlName = sMdlPath.Right(sMdlPath.GetLength()-nPos-1);
			sNewMdlPath = (m_sSoftInStallDir+ APP_DIRECTIRON +L"\\").c_str()+sMdlName;
		}
		WriteMdlNameToFile(sNewMdlPath);
		CopyFile(sMdlPath,sNewMdlPath,FALSE);
		SetMdlPath(sNewMdlPath);
	}
	SetPackagedExePath(sExePath.GetString());
	SetEvbconsoleExePath(GetEnigmavbconsoleFullPath());
	vector<wstring> fileVec;

	WIN32_FIND_DATA FileData;
	HANDLE hSearch; 
	BOOL fFinished = FALSE; 
	wstring strtemp;  
	wstring token = L".";  
	wstring tokend = L".."; 
	wstring filePath = m_sSoftInStallDir+ APP_DIRECTIRON ;
	wstring strFile = filePath + L"\\*.*";
	LPCWSTR lfile = strFile.c_str(); 

	hSearch = FindFirstFile(lfile, &FileData); 
	if (hSearch == INVALID_HANDLE_VALUE) 
	{ 
		return _T("");
	} 

	while (!fFinished) 
	{ 
		strtemp = FileData.cFileName;
		if ((strtemp != token)&& (strtemp != tokend))
		{
			wstring strFile = filePath + L"\\" + strtemp;
			fileVec.push_back(strFile);
		}

		if (!FindNextFile(hSearch, &FileData)) 
		{
			if (GetLastError() == ERROR_NO_MORE_FILES) 
				fFinished = TRUE; 
			else 
				return _T("");
		}
	}

	wstring settingFile = CModelObjOption::GetInstallDir()+L"\\Setting";
	fileVec.push_back(settingFile);
	settingFile = CModelObjOption::GetInstallDir()+L"\\Help";
	fileVec.push_back(settingFile);
	AddFiles(fileVec);

	bool bRet = ExecutePackage();
	if (bRet)
	{
		return sExePath;
	}
	else
	{
		return _T("");
	}
}
